/*
 * Copyright (c) [2005] [Jeffrey Moore]
 *
 * Redistributions in source code form must reproduce the above copyright and 
 * this condition.
 *
 * The contents of this file are subject to the Sun Project JXTA License 
 * Version 1.1 (the "License"); you may not use this file except in compliance 
 * with the License. A copy of the License is available at 
 * http://www.jxta.org/jxta_license.html.
 *
 */

/*
* ViJxtaInviteAction.java
*
* Created on April 15, 2005, 12:53 AM
*/

package net.jxta.myjxta.plugins.vijxta;

import net.jxta.document.*;
import net.jxta.endpoint.MessageElement;
import net.jxta.endpoint.TextDocumentMessageElement;
import net.jxta.logging.Logging;
import net.jxta.myjxta.View;
import net.jxta.myjxta.dialog.Dialog;
import net.jxta.myjxta.dialog.DialogManager;
import net.jxta.myjxta.dialog.DialogMessage;
import net.jxta.myjxta.dialog.util.RemoteCommandInvoker;
import net.jxta.myjxta.util.Group;
import net.jxta.myjxta.util.Peer;
import net.jxta.myjxta.util.Resources;
import net.jxta.myjxta.util.objectmodel.PeerNode;
import net.jxta.pipe.PipeService;
import net.jxta.protocol.PipeAdvertisement;

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * @author Jeff Moore
 */
public class ViJxtaInviteAction extends AbstractAction {


    private static final int INTERVAL = 250;
    private static final int MAX = INTERVAL * 4 * 75;
    private static final Logger LOG = Logger.getLogger(ViJxtaInviteAction.class.getName());

    private View view = null;

    private static final ResourceBundle STRINGS = Resources.getStrings();

    public ViJxtaInviteAction(String name, View view) {
        super(name);

        this.view = view;

        if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) {
            LOG.fine("ViJxtaAction instantiated");
        }
    }

    public boolean isEnabled() {
        PeerNode jxtaNode = (PeerNode) view.getJxtaNode(PeerNode.class);
        return jxtaNode != null; // we need a check that this isnt our own peer
    }

    public void actionPerformed(ActionEvent ae) {
        PeerNode pn = (PeerNode) this.view.getJxtaNode(PeerNode.class);
        final Peer p = pn != null ? pn.getPeer() : null;
        final Group g = pn != null ? pn.getParent().getGroup() : null;
        String status;

        if (p != null &&
                g != null) {
            status = STRINGS.getString("status.command.initiate") +
                    ": " + p.getName();

            if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) {
                LOG.info(status);
            }

            new Thread(new Runnable() {
                public void run() {
                    process(g, p);
                }
            }, getClass().getName() + ":getConnection").start();
        } else {
            String pName=p==null?"null":p.getName();
            status = STRINGS.getString("error.peer.invalid") +
                    " " + pName;

            if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) {
                LOG.severe(status);
            }
        }

        if (status != null) {
            this.view.setStatus(status);
        }
    }

    private void process(Group g, Peer p) {
        LOG.setLevel(Level.INFO);
        String status = "initiating vijxta action";
        this.view.setStatus(status);

        if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) {
            LOG.info(status);
        }

        //get pipe adv from DialogManager - this is the ViJxtaPipe
        StructuredDocument d = getPipeAdv(g);
        //attach it as a message element
        TextDocumentMessageElement te = d != null ?
                new TextDocumentMessageElement(ViJxtaCommand.PIPE,
                        (StructuredTextDocument) d, null) :
                null;


        if (te != null) {


            if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) {
                LOG.info(status);
                LOG.info("instantiating ViJxtaCommand");
            }

            //command fetecher will send out a command on the command pipe
            RemoteCommandInvoker cf = new RemoteCommandInvoker(g, p.getPipeAdvertisement(),
                    new ViJxtaCommand(), this.view.getControl());

            Map<String, MessageElement> m = new HashMap<String, MessageElement>();
            // add the our pipe element
            m.put(ViJxtaCommand.PIPE, te);

            if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) {
                LOG.info("dispatch ViJxta command");
            }

            cf.invoke(MAX, m);
            //get respsonse
            DialogMessage r = cf.getResponse();

            if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) {
                LOG.info("ViJxtaInvitationCommand response: " + r);
            }
            //this is why its important to have a consistent PIPE element in TestCommand
            MessageElement pae = r != null ?
                    r.getMessageElement(ViJxtaCommand.PIPE) :
                    null;

            if (pae != null) {
                status = "vijxta pipe import" +
                        ": " + p.getName();

                this.view.setStatus(status);

                if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) {
                    LOG.info(status);
                    LOG.info("adding dialog");
                }

                ViJxtaDialog dialog = (ViJxtaDialog) DialogManager.getDialog(ViJxtaDialog.class,
                        g, getPipeAdv(pae), this.view.getControl());

                if (dialog == null) {
                    this.view.showMessageDialog("Failed to create Video dialog - are you trying to chat with yourself?");
                } else {
                    dialog.setLocallyInitiated(true);
                    this.view.getControl().addDialog(dialog);
                }
            } else {
                status = "request vijxta pipe" +
                        ": " + p.getName();

                this.view.setStatus(status);

                if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) {
                    LOG.severe(status);
                }
            }
        } else {
            if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) {
                LOG.severe("invalid response");
            }
        }


        LOG.setLevel(Level.SEVERE);
    }

    private PipeAdvertisement getPipeAdv(MessageElement me) {
        if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) {
            LOG.info("get pipeAdv");
        }

        StructuredDocument sd = null;


        if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) {
            LOG.info("me instanceof ByteMessageElement");
        }

        try {
            sd = StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8,
                    me.getStream());
        } catch (IOException ioe) {
            if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) {
                LOG.log(Level.SEVERE, "can\'t document", ioe);
            }
        }


        PipeAdvertisement pa = null;

        if (sd != null) {
            try {
                XMLDocument xml = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8,sd.getStream() );
                pa = (PipeAdvertisement) AdvertisementFactory.
                        newAdvertisement(xml);
            } catch (IOException ioe) {
                if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) {
                    LOG.log(Level.SEVERE, "can\'t get pipe advertisement", ioe);
                }
            }
        }

        return pa;
    }

    private StructuredDocument getPipeAdv(Group g) {
        if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) {
            LOG.info("getPipeAdvl");
        }

        String pn = Dialog.getDialogNamer(ViJxtaDialog.class).
                getDialogName(g.getPeerGroup().getPeerName());
        PipeAdvertisement pa = DialogManager.getInstance(g, pn,
                PipeService.UnicastType).getPipeAdv(g.getPeerGroup());

        return (StructuredDocument) pa.getDocument(MimeMediaType.XMLUTF8);
    }


}
